/*
 * Copyright (c) zero. 2022-2023. All rights reserved.
 *
 */

package com.zero.tool.excel;

import com.zero.tool.excel.annotation.Head;
import com.zero.tool.excel.enums.ExcelVersion;
import com.zero.tool.object.ObjectUtils;
import com.zero.tool.string.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * @ClassName ExcelTool
 * @Description excel对象转成list<T>   或者list<T>转成excel的工具类,很挫，只能处理单sheet页。
 * @Author lin
 * @Date 2022/7/22 下午11:10
 * @Version V1.0
 */
public class ExcelTool {
    private static Logger logger = LoggerFactory.getLogger(ExcelTool.class);
    /**
     * 将数据转换成excel，需要指定类,从类的注解上获取列头
     * */
    public static <T> Workbook parseExcel(ExcelVersion version,List<T> data,Class<T> eClass){
        Workbook workbook = version.equals(ExcelVersion.EXCEL_XLS) ? new HSSFWorkbook() : new XSSFWorkbook();
        // 创建sheet页
        Sheet sheet = createSheet(workbook, eClass);
        // 创建首行
        List<Field> fields = createHeader(sheet, eClass);
        if(data.isEmpty()){
            return workbook;
        }
        // 填充数据
        fillData(sheet,data,fields);
        return workbook;
    }

    /**
     * 将excel转换成List<T> 数据，只处理单sheet页（第一个sheet页数据）。
     * */
    public static <T> List<T> parseList(Workbook workbook, Class<T> imClass){
        Sheet sheet = workbook.getSheetAt(0);
        if (sheet == null) {
            return Collections.emptyList();
        }
        List<T> dataList = new ArrayList();
        Iterator<Row> rowIterator = sheet.rowIterator();
        int startIndex = 0;
        try {
            while (rowIterator.hasNext()){
                Row row = rowIterator.next();
                if(startIndex>0){
                    T t = imClass.newInstance();
                    List<Field> vaildFields = getVaildFields(imClass);
                    for (int i = 0; i < vaildFields.size(); i++) {
                        Cell cell = row.getCell(i);
                        if (cell == null) {
                            continue;
                        }
                        String fieldValueStr = cell.getStringCellValue();
                        Field field = vaildFields.get(i);
                        Object value = fieldValueParse(field,fieldValueStr);
                        field.setAccessible(true);
                        field.set(t,value);
                    }
                    dataList.add(t);
                }
                startIndex++;

            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return dataList;
    }

    private static Object fieldValueParse(Field field, String fieldValueStr) {
        Class<?> type = field.getType();
        if(StringUtils.isEmpty(fieldValueStr)){
            return null;
        }
        if (Boolean.class.equals(type) || Boolean.TYPE.equals(type)) {
            return Boolean.TRUE.toString().equals(fieldValueStr) ? Boolean.TRUE.toString() : Boolean.FALSE.toString();
        } else if (Float.class.equals(type) || Float.TYPE.equals(type)) {
            return Float.valueOf(fieldValueStr);
        } else if (Double.class.equals(type) || Double.TYPE.equals(type)) {
            return Double.valueOf(fieldValueStr);
        } else if (Byte.class.equals(type) || Byte.TYPE.equals(type)) {
            return Byte.valueOf(fieldValueStr);
        } else if (Short.class.equals(type) || Short.TYPE.equals(type)) {
            return Short.valueOf(fieldValueStr);
        } else if (Integer.class.equals(type) || Integer.TYPE.equals(type)) {
            return Integer.valueOf(fieldValueStr);
        } else if (Long.class.equals(type) || Long.TYPE.equals(type)) {
            return Long.valueOf(fieldValueStr);
        } else if (Character.class.equals(type) || Character.TYPE.equals(type)) {
            return fieldValueStr.charAt(0);
        } else if (String.class.equals(type)) {
            return fieldValueStr;
        }
        else{
            logger.error("excel fieldValueParse error,type is {}",type);
            return null;
        }

    }

    private static <T> void fillData(Sheet sheet, List<T> data,List<Field> fields) {
        if (fields == null || fields.size() == 0 || data == null || data.size() == 0) {
            return;
        }
        for (int i = 0; i < data.size(); i++) {
            int index = i+1;
            Row indexRow = sheet.createRow(index);
            T t = data.get(i);
            for (int j = 0; j < fields.size(); j++) {
                Cell cellX = indexRow.createCell(j, CellType.STRING);
                try {
                    fields.get(j).setAccessible(true);
                    cellX.setCellValue(String.valueOf(fields.get(j).get(t)));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    private static List<Field> createHeader(Sheet sheet, Class<?> eClass) {
        Row headRow = sheet.createRow(0);
        // 没有属性直接返回
        if (eClass.getDeclaredFields() == null || eClass.getDeclaredFields().length == 0) {
            return null;
        }
        List<Field> vaildFields = getVaildFields(eClass);
        for (int i = 0,j=0; i < vaildFields.size(); i++) {
            Head head = vaildFields.get(i).getAnnotation(Head.class);
            String fieldName = head.name();
            if(StringUtils.isEmpty(fieldName)){
                fieldName = vaildFields.get(i).getName();
            }
            Cell cellX = headRow.createCell(j++, CellType.STRING);
            cellX.setCellValue(fieldName);
        }
        return vaildFields;
    }

    private static List<Field> getVaildFields(Class<?> eClass) {
        // 按顺序获取属性
        List<Field> vaildFields = new ArrayList<Field>();
        Field[] fields = eClass.getDeclaredFields();
        for (int i = 0,j=0; i < fields.length; i++) {
            Head head = fields[i].getAnnotation(Head.class);
            if(ObjectUtils.isNull(head)){
                continue;
            }
            vaildFields.add(fields[i]);
        }
        return vaildFields;
    }

    private static Sheet createSheet(Workbook workbook, Class<?> eClass) {
        String sheetName = eClass.getAnnotation(com.zero.tool.excel.annotation.Sheet.class).name();
        if(StringUtils.isEmpty(sheetName)){
            sheetName = eClass.getSimpleName();
        }
        return workbook.createSheet(sheetName);
    }



}
